package com.cloudinnov.task;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import com.alibaba.fastjson.JSON;
import com.cloudinnov.dao.EquipmentsDao;
import com.cloudinnov.dao.SectionDao;
import com.cloudinnov.model.EquipmentPoints;
import com.cloudinnov.model.Equipments;
import com.cloudinnov.model.Section;
import com.cloudinnov.utils.support.spring.SpringUtils;
import com.cloudinnov.websocket.ElectricMonitorWebsocket;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

public class ElectricInformationScanJob {

	//获取redis数据是拼接的key形式
	private static final String redisPre = "point:";
	private static final String redisPos= ":value";
	
	//往redis中存异常信息打的前后缀
	private static final String excepPre = "electric:";
	private static final String excepPre1 = "electric:";
	private static final String ULOWER = ":ULOWER";
	private static final String UOVER = ":UOVER";
	private static final String IOVER = ":IOVER";
	private static final String excepPos = ":value";
	
	private static final Integer EXPIRETIIME = 180;
	//异常类型
	private static final String UNDERVOLTAGE = "欠压异常";
	private static final String OVERVOLTAGE = "过压异常";
	private static final String OVERLOAD = "过载异常";
	//异常恢复
	private static final String RECOVER = "异常恢复";
	//电表类型
	private static final String SINGLEAMMETER = "单相电表";
	private static final String THREEAMMETER = "三相电表";
	
	
	
	private ScheduledThreadPoolExecutor executor;
	private EquipmentsDao equipmentsDao = SpringUtils.getBean("equipmentsDao");
	// 恢复数据存放处
	private List<Equipments> exceptionRecover;
	
	JedisPool jedisPool = SpringUtils.getBean("jedisPool");
	// 获取dao的实例对象
	SectionDao sectionDao = SpringUtils.getBean("sectionDao");
	

	public ElectricInformationScanJob() {
		// 初始化中间存储恢复方案
		exceptionRecover = new ArrayList<>();
	}

	/**
	 * 执行线程的方法
	 */
	public void execute() {

		executor = new ScheduledThreadPoolExecutor(1);
		executor.scheduleAtFixedRate(new ElectrictTask(), 2000, 3000, TimeUnit.MILLISECONDS);
	}

	/**
	 * 线程类
	 * @author duyah
	 *
	 */
	class ElectrictTask implements Runnable {

		private Jedis redis;
		private long judgeTime;

		@Override
		public void run() {
			// 获取所有收费站的信息,给线程数赋值
			List<Section> selectSectionEquipmentPoint = sectionDao.selectSectionEquipmentNodeClassPoint();
			for (Section section : selectSectionEquipmentPoint) {
				//调用开启任务的方法
				startJob(section);
			}
		}
		/**
		 * 开启执行job的方法,每个section开启一个
		 * @param section
		 */
		public void startJob(Section section) {
			try {
				redis = jedisPool.getResource();
				// 调用dao方法,获取收费站中所有的设备
				List<Equipments> equipments = section.getSectionEquipments();

				judgeTime = equipments.size() * 1500L;
				// 遍历,获取单个设备
				for (int i = 0; i < equipments.size(); i++) {
					// 开始时间
					long starTime = System.currentTimeMillis();
					// 开始执行电力异常判断任务
					startElectricExceptJudgeJob(equipments.get(i), redis);
					// 结束时间
					long endTime = System.currentTimeMillis();
					long executeTime = endTime - starTime;
//					System.err.println("第"+i+"各设备异常判断过程共用:" + executeTime / 1000d + "秒");
				}

				// 恢复方案轮询
				Set<String> exceptionCode = redis.keys(excepPre + "*");
				if (exceptionCode.size() > 0) {
					for (String redisCode : exceptionCode) {
						String equipmentCode = redisCode.split(":")[1];
						// 调用接口,获取异常的设备信息
						Equipments exceptionEquipment = equipmentsDao.selectEquipmentPointByCode(equipmentCode);
						if (exceptionEquipment != null) {
							exceptionRecover.add(exceptionEquipment);
						}
					}
					for (int i = 0; i < exceptionRecover.size(); i++) {
						// 开始时间
						long starTime = System.currentTimeMillis();
						// 开始电力异常恢复判断任务
						startElectricRecoverJudgeJob(exceptionRecover.get(i), redis);
						// 结束时间
						long endTime = System.currentTimeMillis();
						long executeTime = endTime - starTime;
//						System.err.println("第"+i+"台设备恢复判断过程共用:" + executeTime / 1000d + "秒");
					}
				}
			} catch (Exception e) {
				// 异常信息报错
				e.printStackTrace();
			} finally {
				// 异常设备清除
				exceptionRecover.clear();
				jedisPool.returnResource(redis);
			}
		}

		/**
		 * 进行异常判断任务的方法,分单相和三相
		 * 
		 * @param equipment
		 * @param redis
		 */
		public void startElectricExceptJudgeJob(Equipments equipment, Jedis redis) {
			//根据设备的分类调用对应的判断方法:单相   三相
			String ammeterType = equipment.getAmmeterType();
			//获取数据库中的额定电流并转换成string
			String iValueNormal = equipment.getRatedCurrent()+"";
			//获取设备名称
			String equipmentName = equipment.getName();
			//获取categoryCod值
			String categoryCode = equipment.getCategoryCode();
			//获取location
			String location = equipment.getLocation();
			//单相情况判断
			if (SINGLEAMMETER.equals(ammeterType)) {
				
				//获取数据
				Map<String, String> electric1Value = getElectricValue(equipment, redis);
				//把设备名称放到电力参数集合中
				electric1Value.put("equipmentName", equipmentName);
				//额定电流保存到电力参数集合中
				electric1Value.put("iValueNormal", iValueNormal);
				//把categoryCod值存到电力参数集合中
				electric1Value.put("categoryCode", categoryCode);
				electric1Value.put("location", location);
				// 单相电力异常判断方法:获取电力参数后,对参数进行判断是什么异常
				judgeElectricExceptionMethod(electric1Value, redis);
			}
			
			// 三相的情况, 调用方法,获取单个设备的电力参数
			if (THREEAMMETER.equals(ammeterType)) {
				Map<String, String> electric3Value = getElectric3Value(equipment, redis);
				//把设备名称放到电力参数集合中
				electric3Value.put("equipmentName", equipmentName);
				//额定电流保存到电流参数集合中
				electric3Value.put("iValueNormal", iValueNormal);
				//把categoryCod值存到电力参数集合中
				electric3Value.put("categoryCode", categoryCode);
				electric3Value.put("location", location);
				// 三相电力异常判断方法:获取电力参数后,对参数进行判断是什么异常
				judge3ElectricExceptionMethod(electric3Value, redis);
			}
		}
		
		/**
		 * 获取判断单相异常需要的参数
		 * 
		 * @param equipment
		 * @param redis
		 */
		public Map<String, String> getElectricValue(Equipments equipment, Jedis redis) {
			// 创建返回值参数
			Map<String, String> elecValues = new HashMap<>();

			List<EquipmentPoints> points = equipment.getPoints();
			// 定位的点 equipmentCode
			String equipmentCode = equipment.getCode();

			elecValues = setParamaterValue(points, equipmentCode, redis);

			return elecValues;
		}

		/**
		 * 获取判断三相异常需要的参数
		 * 
		 * @param equipment
		 * @param redis
		 */
		public Map<String, String> getElectric3Value(Equipments equipment, Jedis redis) {
			// 创建返回值参数
			Map<String, String> elecValues = new HashMap<>();

			List<EquipmentPoints> points = equipment.getPoints();
			// 定位的点 equipmentCode
			String equipmentCode = equipment.getCode();

			elecValues = set3ParamaterValue(points, equipmentCode, redis);

			return elecValues;
		}
		
		/**
		 * 针对单相单个设备,匹配对应的电力类型,赋值
		 * 
		 * @param point
		 * @param indexType
		 * @param redis
		 * @return
		 */
		public Map<String, String> setParamaterValue(List<EquipmentPoints> points, String equipmentCode, Jedis redis) {
			// 创建返回值集合
			Map<String, String> elecValues = new HashMap<>();
			// 遍历,获取对应参数的code值
			for (int i = 0; i < points.size(); i++) {
				EquipmentPoints point = points.get(i);
				// 判断标识符
				String indexTypeValue = null;

				String indexType = points.get(i).getIndexType();
				switch (indexType) {
				case "ELECTRICA":
					indexTypeValue = "ELECTRICA";
					break;
				case "UA":
					indexTypeValue = "UA";
					break;
				default:
					// 有异常,需要报出
					
					continue;
				}

				if (indexTypeValue != null) {
					if (indexTypeValue.equals(indexType)) {
						String code = point.getCode();
						String key = redisPre + code + redisPos;
						// 从redis获取值
						String redisValue = redis.lindex(key, 0);
						// 把获取的值放到map集合中取,key值是equipmentCode + 参数类型
						elecValues.put(indexType, redisValue);

						// 获取此时的系统时间
						String currTime = System.currentTimeMillis() + "";
						// 当前系统时间保存到集合中
						elecValues.put(indexType + "Time", currTime);
					}
				}
			}
			// 把equipmentCode存入;
			elecValues.put("equipmentCode", equipmentCode);

			return elecValues;
		}

		/**
		 * 针对三相单个设备,匹配对应的电力类型,赋值
		 * 
		 * @param point
		 * @param indexType
		 * @param redis
		 * @return
		 */
		public Map<String, String> set3ParamaterValue(List<EquipmentPoints> points, String equipmentCode, Jedis redis) {
			// 创建返回值集合
			Map<String, String> elecValues = new HashMap<>();
			// 遍历,获取对应参数的code值
			for (int i = 0; i < points.size(); i++) {
				EquipmentPoints point = points.get(i);
				// 判断标识符
				String indexTypeValue = null;

				String indexType = points.get(i).getIndexType();
				switch (indexType) {
				case "ELECTRICA":
					indexTypeValue = "ELECTRICA";
					break;
				case "ELECTRICB":
					indexTypeValue = "ELECTRICB";
					break;
				case "ELECTRICC":
					indexTypeValue = "ELECTRICC";
					break;
				case "UA":
					indexTypeValue = "UA";
					break;
				case "UB":
					indexTypeValue = "UB";
					break;
				case "UC":
					indexTypeValue = "UC";
					break;
				case "UAB":
					indexTypeValue = "UAB";
					break;
				case "UBC":
					indexTypeValue = "UBC";
					break;
				case "UCA":
					indexTypeValue = "UCA";
					break;
				default:
					// 有异常,需要报出
					continue;
				}

				if (indexTypeValue != null) {
					if (indexTypeValue.equals(indexType)) {
						String code = point.getCode();
						String key = redisPre + code + redisPos;
						// 从redis获取值
						String redisValue = redis.lindex(key, 0);
						// 把获取的值放到map集合中取,key值是equipmentCode + 参数类型
						elecValues.put(indexType, redisValue);

						// 获取此时的系统时间
						String currTime = System.currentTimeMillis() + "";
						// 当前系统时间保存到集合中
						elecValues.put(indexType + "Time", currTime);
					}
				}
			}
			// 把equipmentCode存入;
			elecValues.put("equipmentCode", equipmentCode);

			return elecValues;
		}

		/**
		 * 根据单相电力参数判定是什么异常
		 * 
		 * @param electricValue
		 */
		public void judgeElectricExceptionMethod(Map<String, String> electricValue, Jedis redis) {
			//电压的标识
			String tagU = "UA";
			// 获取单相的电力参数
			Map<String, String> uaParamaterValue = get3ParamaterValue(electricValue, tagU);
			//电流的标识
			String tagI = "ELECTRICA";
			// 获取单相的电力参数
			Map<String, String> iaParamaterValue = get3ParamaterValue(electricValue, tagI);
			
			// 判断单相欠压,调用单相欠压方法
			boolean uLowerMark = u3JudgeLower(tagU, uaParamaterValue, redis);
			if (uLowerMark) {
				String exceptionCode = uaParamaterValue.get("equipmentCode");
				//获取设备名称
				String equipmentName = uaParamaterValue.get("equipmentName");
				//获取设备标识符
				String categoryCode = uaParamaterValue.get("categoryCode");
				String location = uaParamaterValue.get("location");
				
				//此处用于依据redis的值判断是第一次还是第二次出现,先获取再判断:无值,第一次异常,发消息通知;有值不是第一次,设成2
				Set<String> redisKeys = redis.keys(excepPre1 + exceptionCode + ULOWER + "*");
				if (redisKeys.size() == 0) {
					//往redis中存储异常信息
					redis.set(excepPre1 + exceptionCode + ULOWER + excepPos, equipmentName + ":" + UNDERVOLTAGE);
					//为异常信息设置有效时间: 三分钟
//					redis.expire(excepPre1 + exceptionCode + ULOWER + excepPos, EXPIRETIIME);
					//调报欠压情况,往前台发消息的方法
					Map<String, String> alarmMsgMap = excep2Map(categoryCode, exceptionCode, location, equipmentName, UNDERVOLTAGE);
					try {
						//调用socket的方法,往前端发送信息
						sendMsg(alarmMsgMap);
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
			// 判断单相过压,调用单相过压方法
			boolean uOverMark = u3JudgeOver(tagU, uaParamaterValue, redis);
			if (uOverMark) {
				String exceptionCode = uaParamaterValue.get("equipmentCode");
				String equipmentName = uaParamaterValue.get("equipmentName");
				//获取设备标识符
				String categoryCode = uaParamaterValue.get("categoryCode");
				String location = uaParamaterValue.get("location");
				//此处用于依据redis的值判断是第一次还是第二次出现,先获取再判断:无值,第一次异常,发消息通知;有值不是第一次,设成2
				Set<String> redisKeys = redis.keys(excepPre1 + exceptionCode + UOVER + "*");
				if (redisKeys.size() == 0) {
					redis.set(excepPre1 + exceptionCode + UOVER + excepPos, equipmentName + ":" + OVERVOLTAGE);
					//设置失效时间
//					redis.expire(excepPre1 + exceptionCode + UOVER + excepPos, EXPIRETIIME);
					//调报过压情况,往前台发消息的方法
					Map<String, String> alarmMsgMap = excep2Map(categoryCode, exceptionCode, location, equipmentName, OVERVOLTAGE);
					try {
						//调用socket的方法,往前端发送信息
						sendMsg(alarmMsgMap);
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
			// 判断单相过载,调用单相过载方法
			boolean iMark = i3JudgeOver(tagI, iaParamaterValue, redis);
			if (iMark) {
				String exceptionCode = iaParamaterValue.get("equipmentCode");
				//获取设备名称
				String equipmentName = iaParamaterValue.get("equipmentName");
				//获取设备标识符
				String categoryCode = iaParamaterValue.get("categoryCode");
				String location = iaParamaterValue.get("location");
				//此处用于依据redis的值判断是第一次还是第二次出现,先获取再判断:无值,第一次异常,发消息通知;有值不是第一次,设成2
				Set<String> redisKeys = redis.keys(excepPre1 + exceptionCode + IOVER + "*");
				if (redisKeys.size() == 0) {
					redis.set(excepPre1 + exceptionCode + IOVER + excepPos, equipmentName + ":" + OVERLOAD);
					//设置失效时间
//					redis.expire(excepPre1 + exceptionCode + IOVER + excepPos, EXPIRETIIME);
					//调报过压情况,往前台发消息的方法
					Map<String, String> alarmMsgMap = excep2Map(categoryCode, exceptionCode, location, equipmentName, OVERLOAD);
					try {
						//调用socket的方法,往前端发送信息
						sendMsg(alarmMsgMap);
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
		
		/**
		 * 根据三相电力参数判定是什么异常
		 * 
		 * @param electricValue
		 */
		public void judge3ElectricExceptionMethod(Map<String, String> electricValue, Jedis redis) {
			// 对欠三相压异常进行判断,返回对应的判断结果
			List<Boolean> uLowerList = new ArrayList<>(); //欠压
			List<Boolean> uOverList = new ArrayList<>(); //过压
			List<Boolean> iOverList = new ArrayList<>(); //过载
			// 对欠三相压异常进行判断,获取的是电压的值
			String tag = null;

			String[] keyStrsU = { "UA", "UB", "UC", "UAB", "UBC", "UCA" };
			// 循环遍历,判断是否异常
			for (int i = 0; i < keyStrsU.length; i++) {
				tag = keyStrsU[i];
				// 判断三相欠压,调用三相欠压方法
				boolean uLowerMark = is3UnderVoltage(electricValue, redis, tag);
				uLowerList.add(uLowerMark);
				// 判断三相过压,调用三相过压方法
				boolean uOverMark = is3OverVoltage(electricValue, redis, tag);
				uOverList.add(uOverMark);
			}
			String[] keyStrsI = { "ELECTRICA", "ELECTRICB", "ELECTRICC" };
			for (int i = 0; i < keyStrsI.length; i++) {
				tag = keyStrsI[i];
				// 判断三相过载,调用三相过载方法
				boolean iOverMark = is3OverLoad(electricValue, redis, tag);
				iOverList.add(iOverMark);
			}
			
			//对返回的结果进行判断,发送异常类型
			//欠压
			int num = 0;
			for (int i = 0; i < uLowerList.size(); i++) {
				if (uLowerList.get(i)) {
					num++;
				}
			}
			if (num != 0) {
				String exceptionCode = electricValue.get("equipmentCode");
				//获取设备名称
				String equipmentName = electricValue.get("equipmentName");
				//获取设备标识符
				String categoryCode = electricValue.get("categoryCode");
				String location = electricValue.get("location");
				//此处用于依据redis的值判断是第一次还是第二次出现,先获取再判断:无值,第一次异常,发消息通知;有值不是第一次,设成2
				Set<String> redisKeys = redis.keys(excepPre1 + exceptionCode + ULOWER + "*");
				if (redisKeys.size() == 0) {
					redis.set(excepPre1 + exceptionCode + ULOWER + excepPos, equipmentName + ":" + UNDERVOLTAGE);
					//设置失效时间
//					redis.expire(excepPre1 + exceptionCode + ULOWER + excepPos, EXPIRETIIME);
					//调报过压情况,往前台发消息的方法
					Map<String, String> alarmMsgMap = excep2Map(categoryCode, exceptionCode, location, equipmentName, UNDERVOLTAGE);
					try {
						//调用socket的方法,往前端发送信息
						sendMsg(alarmMsgMap);
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
			//过压
			num = 0;
			for (int i = 0; i < uOverList.size(); i++) {
				if (uOverList.get(i)) {
					num++;
				}
			}
			//发送过压信息
			if (num != 0) {
				String exceptionCode = electricValue.get("equipmentCode");
				//获取设备名称
				String equipmentName = electricValue.get("equipmentName");
				//获取设备标识符
				String categoryCode = electricValue.get("categoryCode");
				String location = electricValue.get("location");
				//此处用于依据redis的值判断是第一次还是第二次出现,先获取再判断:无值,第一次异常,发消息通知;有值不是第一次,设成2
				Set<String> redisKeys = redis.keys(excepPre1 + exceptionCode + UOVER + "*");
				if (redisKeys.size() == 0) {
					redis.set(excepPre1 + exceptionCode + UOVER + excepPos, equipmentName + ":" + OVERVOLTAGE);
					//设置失效时间
//					redis.expire(excepPre1 + exceptionCode + UOVER + excepPos, EXPIRETIIME);
					//调报过压情况,往前台发消息的方法
					Map<String, String> alarmMsgMap = excep2Map(categoryCode, exceptionCode, location, equipmentName, OVERVOLTAGE);
					try {
						//调用socket的方法,往前端发送信息
						sendMsg(alarmMsgMap);
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
			//过载
			num = 0;
			for (int i = 0; i < iOverList.size(); i++) {
				if (iOverList.get(i)) {
					num++;
				}
			}
			if (num != 0) {
				String exceptionCode = electricValue.get("equipmentCode");
				//获取设备名称
				String equipmentName = electricValue.get("equipmentName");
				//获取设备标识符
				String categoryCode = electricValue.get("categoryCode");
				String location = electricValue.get("location");
				//此处用于依据redis的值判断是第一次还是第二次出现,先获取再判断:无值,第一次异常,发消息通知;有值不是第一次,设成2
				Set<String> redisKeys = redis.keys(excepPre1 + exceptionCode + IOVER + "*");
				if (redisKeys.size() == 0) {
					redis.set(excepPre1 + exceptionCode + IOVER + excepPos, equipmentName + ":" + OVERLOAD);
					//设置失效时间
//					redis.expire(excepPre1 + exceptionCode + IOVER + excepPos, EXPIRETIIME);
					//调报过压情况,往前台发消息的方法
					Map<String, String> alarmMsgMap = excep2Map(categoryCode, exceptionCode, location, equipmentName, OVERLOAD);
					try {
						//调用socket的方法,往前端发送信息
						sendMsg(alarmMsgMap);
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}

		/**
		 * 判断三相欠压的方法
		 * 
		 * @param electricValue
		 * @param redis
		 * @param tag 传来的标识符,确定获取谁的值
		 *            
		 */
		public boolean is3UnderVoltage(Map<String, String> electricValue, Jedis redis, String tag) {
			// 根据tag,调用getParamaterValue方法,获取对应的值(一个电力数据的各种值)
			Map<String, String> paramaterValue = get3ParamaterValue(electricValue, tag);

			// 调用欠压的判断方法
			boolean mark = u3JudgeLower(tag, paramaterValue, redis);
			return mark;
		}

		/**
		 * 给出三相电压判断是否欠压
		 * 
		 * @param keyStr
		 * @param paramaterValue
		 */
		public boolean u3JudgeLower(String tag, Map<String, String> paramaterValue, Jedis redis) {
			//返回的标识符
			boolean mark = false;
			
			// 获取redis内存的时间戳
			String redisTime = paramaterValue.get("redisTime" + tag).toString();
			// 获取redis时的系统时间
			String currTime = paramaterValue.get("currTime" + tag).toString();
			// 调用时间差判断方法,小于设定值是true
			boolean flag = dJudgeTime(redisTime, currTime);

			// 相电压判断
			if (tag.length() == 2) {
				if (flag) {
					// 欠压相电压小于187v, 线电压低于323v
					if (Double.parseDouble(paramaterValue.get(tag).toString()) < 187d && Double.parseDouble(paramaterValue.get(tag).toString()) != 0d) {
						
						mark = true;
					}
				}
			}
			// 线电压判断
			if (tag.length() == 3) {
				if (flag) {
					// 欠压相电压小于187v, 线电压低于323v
					if (Double.parseDouble(paramaterValue.get(tag).toString()) < 323d && Double.parseDouble(paramaterValue.get(tag).toString()) != 0d) {
						
						mark = true;
					}
				}
			}
			return mark;
		}

		/**
		 * 判断三相过压的方法
		 * 
		 * @param electricValue
		 * @param redis
		 * @param tag
		 */
		public boolean is3OverVoltage(Map<String, String> electricValue, Jedis redis, String tag) {
			// 根据tag,调用getParamaterValue方法,获取对应的值(一个电力数据的各种值)
			Map<String, String> paramaterValue = get3ParamaterValue(electricValue, tag);

			// 调用电压的判断方法
			boolean mark = u3JudgeOver(tag, paramaterValue, redis);
			return mark;
		}

		/**
		 * 给出三相电压判断是否过压
		 * 
		 * @param tag
		 * @param paramaterValue
		 */
		public boolean u3JudgeOver(String tag, Map<String, String> paramaterValue, Jedis redis) {
			//返回标识
			boolean mark = false;
			
			// 获取redis内存的时间戳
			String redisTime = paramaterValue.get("redisTime" + tag).toString();
			// 获取redis时的系统时间
			String currTime = paramaterValue.get("currTime" + tag).toString();
			// 调用时间差判断方法,小于设定值是true
			boolean flag = dJudgeTime(redisTime, currTime);
			
			// 相电压判断
			if (tag.length() == 2) {
				if (flag) {
					// 过压相电压大于253
					if (Double.parseDouble(paramaterValue.get(tag).toString()) > 253d) {
						
						mark = true;
					}
				}
			}
			// 线电压判断
			if (tag.length() == 3) {
				if (flag) {
					// 线电压大于437
					if (Double.parseDouble(paramaterValue.get(tag).toString()) > 437d) {
						mark = true;
					}
				}
			}
			return mark;
		}

		/**
		 * 判断三相过载的方法
		 * 
		 * @param electricValue
		 * @param redis
		 * @param tag
		 */
		public boolean is3OverLoad(Map<String, String> electricValue, Jedis redis, String tag) {
			// 根据tag,调用getParamaterValue方法,获取对应的值(一个电力数据的各种值)
			Map<String, String> paramaterValue = get3ParamaterValue(electricValue, tag);
			// 调用电压的判断方法
			boolean mark = i3JudgeOver(tag, paramaterValue, redis);
			return mark;
		}

		/**
		 * 给出三相电流判断是否过载
		 * 
		 * @param keyStr
		 * @param paramaterValue
		 */
		public boolean i3JudgeOver(String tag, Map<String, String> paramaterValue, Jedis redis) {
			//创建返回值
			boolean mark = false;
			// 获取redis内存的时间戳
			String redisTime = paramaterValue.get("redisTime" + tag);
			// 获取redis时的系统时间
			String currTime = paramaterValue.get("currTime" + tag);
			// 调用时间差判断方法,小于设定值是true
			boolean flag = dJudgeTime(redisTime, currTime);
			//获取额定电流
			double I = Double.parseDouble(paramaterValue.get("iValueNormal"));
			//获取redis存储的电力数
			double iRedis = Double.parseDouble(paramaterValue.get(tag));
			// 电流过载判断
			if (flag) {
				// 过载电流的值超过额定电流的15%
				if (iRedis > (I * 1.15d)) {
					//返回的标识符
					mark = true;
				}
			}
			return mark;
		}

		/**
		 * 进行三相电力异常恢复判断的方法,分单相和三相
		 * 
		 * @param equipment
		 * @param redis
		 */
		public void startElectricRecoverJudgeJob(Equipments equipment, Jedis redis) {
			//电表类型
			String ammeterType = equipment.getAmmeterType();
			//获取设备名称
			String equipmentName = equipment.getName();
			//获取额定电流
			String iValueNormal = equipment.getRatedCurrent()+"";
			//获取categoryCod值
			String categoryCode = equipment.getCategoryCode();
			
			//单相电力恢复判断
			if (SINGLEAMMETER.equals(ammeterType)) {
				Map<String, String> electric1Value = getElectricValue(equipment, redis);
				//把把设备名称放到判断恢复的电力参数集合中
				electric1Value.put("equipmentName", equipmentName);
				//额定电流保存到电流参数集合中
				electric1Value.put("iValueNormal", iValueNormal);
				//把categoryCod值存到电力参数集合中
				electric1Value.put("categoryCode", categoryCode);
				// 电力异常恢复判断方法,跟据数据判断是否恢复
				judgeElectricExceptionRecoMethod(electric1Value, redis);
			}
			
			//三相电力恢复判断
			if (THREEAMMETER.equals(ammeterType)) {
				// 调用方法,获取单个设备的电力参数,对是否恢复进行判断
				Map<String, String> electric3Value = getElectric3Value(equipment, redis);
				//把设备名称放到判断恢复的电力参数集合中
				electric3Value.put("equipmentName", equipmentName);
				//额定电流保存到电流参数集合中
				electric3Value.put("iValueNormal", iValueNormal);
				//把categoryCod值存到电力参数集合中
				electric3Value.put("categoryCode", categoryCode);
				// 电力异常恢复判断方法,跟据数据判断是否恢复
				judge3ElectricExceptionRecoMethod(electric3Value, redis);
			}
		}
		
		/**
		 * 根据传来的单相电力数据判断异常是否恢复
		 * 
		 * @param electricValue
		 * @param redis
		 */
		public void judgeElectricExceptionRecoMethod(Map<String, String> electric1Value, Jedis redis) {
			//各个情况判断后返回值存储位置
			List<String> judgeTag = new ArrayList<>();
			//电流的标识
			String tagI = "ELECTRICA";
			// 获取单相的电力参数
			Map<String, String> iaParamaterValue = get3ParamaterValue(electric1Value, tagI);
			// 判断单相过载,调用单相过载方法
			String reValue1 = i3JudgeOverReco(tagI, iaParamaterValue);
			judgeTag.add(reValue1);
			//电压的标识
			String tagU = "UA";
			// 获取单相的电力参数
			Map<String, String> uaParamaterValue = get3ParamaterValue(electric1Value, tagU);
			// 判断相欠压,调用单相欠压方法
			String reValue2 = u3JudgeLowerReco(tagU, uaParamaterValue);
			judgeTag.add(reValue2);
			// 判断相过压,调用单相过压方法
			String reValue3 = u3JudgeOverReco(tagU, uaParamaterValue);
			judgeTag.add(reValue3);
			int a = 0;
			for (int i = 0; i < judgeTag.size(); i++) {
				if ("true".equals(judgeTag.get(i))) {
					a++;
				}
			}
			if (a == judgeTag.size()) {
				// 判断异常已经恢复,删除redis中的异常记录
				String exceptionCode = electric1Value.get("equipmentCode");
				String equipmentName = electric1Value.get("equipmentName");
				//获取设备标识符
				String categoryCode = electric1Value.get("categoryCode");
				String location = electric1Value.get("location");
				//所有异常恢复,删除redis中的所有异常
				redis.del(excepPre1 + exceptionCode + ULOWER + excepPos);
				redis.del(excepPre1 + exceptionCode + UOVER + excepPos);
				redis.del(excepPre1 + exceptionCode + IOVER + excepPos);
				//删除断路,短路异常信息
				redis.del(excepPre1 + exceptionCode + excepPos);
				//调封装数据的方法,往前端发送消息
				Map<String, String> alarmMsgMap = excep2Map(categoryCode, exceptionCode, location, equipmentName, RECOVER);
				try {
					//调用socket的方法,往前端发送信息
					sendMsg(alarmMsgMap);
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
		/**
		 * 根据传来的三相电力数据判断异常是否恢复
		 * 
		 * @param electricValue
		 * @param redis
		 */
		public void judge3ElectricExceptionRecoMethod(Map<String, String> electric3Value, Jedis redis) {
			// 对欠压异常进行判断,获取的是电压的值
			String tag = null;
			//各个情况判断后返回值存储位置
			List<String> judgeTag = new ArrayList<>();
			String[] keyStrsU = { "UA", "UB", "UC", "UAB", "UBC", "UCA" };
			// 循环遍历电压,判断是否异常
			for (int i = 0; i < keyStrsU.length; i++) {
				tag = keyStrsU[i];
				// 再判断欠压是否恢复,调用方法
				String reValue1 = is3UnderVoltageReco(electric3Value, redis, tag);
				judgeTag.add(reValue1);

				// 先判断过压是否恢复,调用方法
				String reValue2 = is3OverVoltageReco(electric3Value, redis, tag);
				judgeTag.add(reValue2);
			}
			// 循环遍历电流,判断是否异常
			String[] keyStrsI = { "ELECTRICA", "ELECTRICB", "ELECTRICC" };
			for (int i = 0; i < keyStrsI.length; i++) {
				tag = keyStrsI[i];
				// 判断过载是否恢复,调用方法
				String reValue3 = is3OverLoadReco(electric3Value, redis, tag);
				judgeTag.add(reValue3);
			}
			int a = 0;
			for (int i = 0; i < judgeTag.size(); i++) {
				if ("true".equals(judgeTag.get(i))) {
					a++;
				}
			}
			if (a == judgeTag.size()) {
				// 判断异常已经恢复,删除redis中的异常记录
				String exceptionCode = electric3Value.get("equipmentCode");
				String equipmentName = electric3Value.get("equipmentName");
				//获取设备标识符
				String categoryCode = electric3Value.get("categoryCode");
				String location = electric3Value.get("location");
				//删除redis中的保存异常信息
				redis.del(excepPre1 + exceptionCode + ULOWER + excepPos);
				redis.del(excepPre1 + exceptionCode + UOVER + excepPos);
				redis.del(excepPre1 + exceptionCode + IOVER + excepPos);
				//删除断路,短路的异常信息
				redis.del(excepPre1 + exceptionCode + excepPos);
				
				//调封装数据的方法,往前端发送消息
				Map<String, String> alarmMsgMap = excep2Map(categoryCode, exceptionCode, location, equipmentName, RECOVER);
				try {
					//调用socket的方法,往前端发送信息
					sendMsg(alarmMsgMap);
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

		/**
		 * 判断三相欠压是否恢复的方法
		 * 
		 * @param electricValue
		 * @param redis
		 * @param tag
		 */
		public String is3UnderVoltageReco(Map<String, String> electricValue, Jedis redis, String tag) {

			// 调用getParamaterValue方法,获取对应的值
			Map<String, String> paramaterValue = get3ParamaterValue(electricValue, tag);

			// 调用电压的判断方法
			String reco = u3JudgeLowerReco(tag, paramaterValue);

			// 把一次判断的结果返回
			return reco;
		}

		/**
		 * 给出三相电压判断欠压是否恢复方法
		 * 
		 * @param keyStr
		 * @param paramaterValue
		 */
		public String u3JudgeLowerReco(String tag, Map<String, String> paramaterValue) {
			// 获取redis内存的时间戳
			String redisTime = paramaterValue.get("redisTime" + tag);
			// 获取redis时的系统时间
			String currTime = paramaterValue.get("currTime" + tag);
			// 调用时间差判断方法,小于设定值是true
			boolean flag = dJudgeTime(redisTime, currTime);

			// 相电压判断
			if (tag.length() == 2) {
				if (flag) {
					// 欠压恢复相电压高于198v,
					if (Double.parseDouble(paramaterValue.get(tag)) > 198d) {
						// 此时这个值正常,给个标识符
						return "true";
					}
				}
			}

			// 线电压欠压恢复判断,线电压高于342v
			if (tag.length() == 3) {
				if (flag) {
					// 欠压恢复判断, 线电压高于342v
					if (Double.parseDouble(paramaterValue.get(tag)) > 342d) {
						// 此时这个值正常,给个标识符
						return "true";
					}
				}
			}
			return "false";
		}

		/**
		 * 判断三相过压恢复的方法
		 * 
		 * @param electricValue
		 * @param redis
		 * @param tag
		 */
		public String is3OverVoltageReco(Map<String, String> electricValue, Jedis redis, String tag) {
			// 调用getParamaterValue方法,获取对应的值
			Map<String, String> paramaterValue = get3ParamaterValue(electricValue, tag);

			// 调用电压的判断方法
			String reco = u3JudgeOverReco(tag, paramaterValue);

			// 把一次判断的结果返回
			return reco;
		}

		/**
		 * 给出三相电压判断过压是否恢复方法
		 * 
		 * @param keyStr
		 * @param paramaterValue
		 */
		public String u3JudgeOverReco(String tag, Map<String, String> paramaterValue) {
			// 获取redis内存的时间戳
			String redisTime = paramaterValue.get("redisTime" + tag);
			// 获取redis时的系统时间
			String currTime = paramaterValue.get("currTime" + tag);
			// 调用时间差判断方法,小于设定值是true
			boolean flag = dJudgeTime(redisTime, currTime);

			// 相电压判断,过压恢复相电压低于242v,
			if (tag.length() == 2) {
				if (flag) {
					// 过压恢复相电压低于242v,
					if (Double.parseDouble(paramaterValue.get(tag)) < 242d && Double.parseDouble(paramaterValue.get(tag)) != 0d) {
						// 此时这个值正常,给个标识符
						return "true";
					}
				}
			}

			// 线电压过压恢复判断,线电压低于418v
			if (tag.length() == 3) {
				if (flag) {
					// 过压恢复判断, 线电压低于418v
					if (Double.parseDouble(paramaterValue.get(tag)) < 418d && Double.parseDouble(paramaterValue.get(tag)) != 0d) {
						// 此时这个值正常,给个标识符
						return "true";
					}
				}
			}
			return "false";
		}

		/**
		 * 判断三相过载是否恢复的方法
		 * 
		 * @param electricValue
		 * @param redis
		 * @param tag
		 */
		public String is3OverLoadReco(Map<String, String> electricValue, Jedis redis, String tag) {
			// 调用get3ParamaterValue方法,获取对应的值
			Map<String, String> paramaterValue = get3ParamaterValue(electricValue, tag);

			// 调用电流过载的判断方法
			String reco = i3JudgeOverReco(tag, paramaterValue);

			// 把一次判断的结果返回
			return reco;
		}

		/**
		 * 给出三相电流判断过载是否恢复
		 * 
		 * @param tag
		 *            标识符,要获取对象的值
		 * @param paramaterValue
		 */
		public String i3JudgeOverReco(String tag, Map<String, String> paramaterValue) {
			// 获取redis中存储的时间戳
			String time = paramaterValue.get("redisTime" + tag);
			// 获取取redis数据时的系统时间
			String currTime = paramaterValue.get("currTime" + tag);
			// 调用时间差判断方法,小于设定值是true,此时没有断电
			boolean flag = dJudgeTime(time, currTime);
			//获取额定电流
			double I = Double.parseDouble(paramaterValue.get("iValueNormal"));
			//获取redis存储的电力数
			double iRedis = Double.parseDouble(paramaterValue.get(tag));
			// 电流过载判断
			if (flag) {
				// 过载电流的值低过额定电流的10%
				if (iRedis != 0d && iRedis< (I * 1.1d) ) {
					// 过载情况恢复
					return "true";
				}
			}
			return "false";
		}

		/**
		 * 获取需要的三相电力数据方法,针对传入的电力标识符,返回对应的结果(一个参数对应的值,redis时间/对应的值/获取redis时的系统时间)
		 * 
		 * @param electricValue
		 * @param tag
		 */
		public Map<String, String> get3ParamaterValue(Map<String, String> electricValue, String tag) {
			Map<String, String> returnValue = new HashMap<>();

			// 遍历集合,匹配对应的参数获取值
			for (String key : electricValue.keySet()) {
				if (tag.equals(key)) {
					returnValue.put("redisTime" + key, electricValue.get(key).split(",")[0]);
					returnValue.put(key, electricValue.get(key).split(",")[1]);
					returnValue.put("currTime" + key, electricValue.get(key + "Time"));
				}
			}
			// 获取电压时,把equipmentCode值也返回
			returnValue.put("equipmentCode", electricValue.get("equipmentCode"));
			//把设备名称放到获取设备单个参数的集合中
			returnValue.put("equipmentName", electricValue.get("equipmentName"));
			//把额定电流放到获取设备单个参数的集合中
			returnValue.put("iValueNormal", electricValue.get("iValueNormal"));
			//把categoryCode放到获取设备单个参数的集合中
			returnValue.put("categoryCode", electricValue.get("categoryCode"));
			returnValue.put("location", electricValue.get("location"));
			return returnValue;
		}

		/**
		 * 获取和当前时间差值,与预设的时间差进行比较,大于false,小于true
		 * 
		 * @param redisTime
		 * @param currTime
		 * @return
		 */
		public boolean dJudgeTime(String time1, String time2) {
			boolean flag = false;
			Long times = Long.parseLong(time1);
			// 获取当前系统时间
			Long currTime = Long.parseLong(time2);
			// 做差值进行判断
			long dJudgeTime = (currTime - times * 1000l);

			// 此处的 judgeTime 需要debug验证
			if (dJudgeTime < judgeTime) {
				flag = true;
			}
			return flag;
		}

		/**
		 * 封装异常信息到map集合,并把异常信息存到redis
		 * @param tag
		 * @param paramaterValue
		 * @param redis
		 */
		public Map<String, String> excep2Map(String categoryCode, String exceptionCode, String equipmentName, String location, String exceptionType) {
			Map<String,String> alarmMsgMap = new HashMap<>();
			
			// 报过载情况,往前台发消息
			alarmMsgMap.put("categoryCode", categoryCode); //设备标识符
			alarmMsgMap.put("equipCode", exceptionCode); //设备code值
			alarmMsgMap.put("faultType", exceptionType); //异常类型
			alarmMsgMap.put("equipName", equipmentName); //设备名称
			alarmMsgMap.put("location", location);
			
			if (UNDERVOLTAGE.equals(exceptionType)) {
				alarmMsgMap.put("msgType", "electricAlarm"); //异常分类:异常
				alarmMsgMap.put("solutionAdvice", "电路欠压,检查该回路是否接触不良"); //建议
			}
			if (OVERVOLTAGE.equals(exceptionType)) {
				alarmMsgMap.put("msgType", "electricAlarm"); //异常分类
				alarmMsgMap.put("solutionAdvice", "电路过压,检测变压器是否工作正常"); //建议
			}
			if (OVERLOAD.equals(exceptionType)) {
				alarmMsgMap.put("msgType", "electricAlarm"); //异常分类
				alarmMsgMap.put("solutionAdvice", "电路过载,(1)检查是否大功率电器接入回路；(2)检查回路所带电器是否出现故障。"); //建议
			}
			if (RECOVER.equals(exceptionType)) {
				alarmMsgMap.put("msgType", "electricRecover"); //异常分类:恢复
			}
			
			return alarmMsgMap;
		}
		
		/**
		 * 调用websocket的方法,向前端发送信息
		 * 
		 * @param data
		 * @throws IOException
		 */
		public void sendMsg(Map<String, String> data) throws IOException {
			Iterator<Map.Entry<String, ElectricMonitorWebsocket>> equipmentStateWebsocket = ElectricMonitorWebsocket.webSocketMap
					.entrySet().iterator();
			while (equipmentStateWebsocket.hasNext()) {
				Map.Entry<String, ElectricMonitorWebsocket> electricWebsocketEntry = equipmentStateWebsocket.next();
				electricWebsocketEntry.getValue().sendMessage(JSON.toJSONString(data));
			}
		}

	}
}
